package io.singulart.bottomnavigationbar;

import static io.singulart.bottomnavigationbar.Constants.USER_CLICK_OFFSET;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.element.VectorElement;
import ohos.agp.render.BlendMode;
import ohos.agp.render.Canvas;
import ohos.agp.render.ColorFilter;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;

/**
 * Bottom NavigationBar
 */
public class BottomNavigationBar extends Component implements Component.DrawTask, Component.TouchEventListener {
    private int mBarColor;

    private int mItemSelectedColor;

    private float mTopLeftRadius;
    private float mTopRightRadius;

    private float mShadowRadius;

    private float mCutoutDeep;
    private float mCutoutButtonOffset;
    private float mBnbCutoutLeftTop_radius;
    private float mBnbCutoutRightTop_radius;
    private float mBnbCutoutBottomLeft_radius;
    private float mBnbCutoutBottomRight_radius;

    private float mTextItemSize;
    private int mTextItemColor;

    private boolean mIsBtnInCenter = true;

    private int mLastSelectedItem;

    private String[] mBtnTextStr;

    private CenterNavigationButton mCenterNavigationButton;

    private OnItemSelectedListener mOnItemSelectedListener;

    private Path mBackPath = new Path();

    private RectFloat mRadiusRect = new RectFloat();

    private Paint mBackPaint = new Paint();

    private Paint mCenterBtnPaint = new Paint();

    private Paint mTextPaint = new Paint();

    private Paint mIconPaint = new Paint();

    private VectorPixelMap[] mVectorPixelMapElement;
    private Rect textRect = new Rect();

    public BottomNavigationBar(Context context) {
        this(context, null);
    }

    public BottomNavigationBar(Context context, AttrSet attrs) {
        this(context, attrs, null);
    }

    public BottomNavigationBar(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init(attrSet);
    }

    /**
     * set CenterNavigationButton
     *
     * @param centerNavigationButton CenterNavigationButton
     */
    public void setCenterNavigationButton(CenterNavigationButton centerNavigationButton) {
        this.mCenterNavigationButton = centerNavigationButton;
    }

    private void init(AttrSet attributeSet) {
        if (attributeSet != null) {
            mBarColor = AttrUtils.getAttrSetColor(attributeSet, "bnb_background_color", Color.WHITE);
            mItemSelectedColor = AttrUtils.getAttrSetColor(attributeSet, "bnb_item_selected_color", Color.WHITE);

            mTopLeftRadius = AttrUtils.getDimension(attributeSet, "bnb_top_left_radius", 100);
            mTopRightRadius = AttrUtils.getDimension(attributeSet, "bnb_top_right_radius", 100);

            mShadowRadius = AttrUtils.getDimension(attributeSet, "bnb_shadow_radius", 12);

            mIsBtnInCenter = AttrUtils.getBoolean(attributeSet, "bnb_center_btn", false);

            mCutoutDeep = AttrUtils.getDimension(attributeSet, "bnb_cutout_deep", 0);
            mCutoutButtonOffset = AttrUtils.getDimension(attributeSet, "bnb_cutout_bottom_offset", 0);
            mBnbCutoutLeftTop_radius = AttrUtils.getDimension(attributeSet, "bnb_cutout_leftTop_radius", 0);
            mBnbCutoutRightTop_radius = AttrUtils.getDimension(attributeSet, "bnb_cutout_rightTop_radius", 0);
            mBnbCutoutBottomLeft_radius = AttrUtils.getDimension(attributeSet, "bnb_cutout_bottomLeft_radius", 0);
            mBnbCutoutBottomRight_radius = AttrUtils.getDimension(attributeSet, "bnb_cutout_bottomRight_radius", 0);

            mTextItemSize = AttrUtils.getDimension(attributeSet, "bnb_text_item_size", 10);
            mTextItemColor =
                    AttrUtils.getAttrSetColor(
                            attributeSet, "bnb_text_item_color", new Color(Color.getIntColor("#666DA5")));

            String btnText = AttrUtils.getString(attributeSet, "btn_title", null);
            if (btnText != null && !btnText.isEmpty()) {
                mBtnTextStr = btnText.split("/");
            } else {
                mBtnTextStr = new String[] {"null", "null", "null", "null", "null"};
            }
        }
        setUp();
        addDrawTask(this);
        setTouchEventListener(this);
        invalidate();
    }

    private void setUp() {
        mBackPaint.setAntiAlias(true);
        mBackPaint.setColor(new Color(mBarColor));
        mBackPaint.setStyle(Paint.Style.FILL_STYLE);

        mCenterBtnPaint.setAntiAlias(true);
        mCenterBtnPaint.setColor(Color.WHITE);
        mCenterBtnPaint.setStyle(Paint.Style.FILL_STYLE);

        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextSize((int) mTextItemSize);
        mTextPaint.setColor(new Color(mTextItemColor));

        mIconPaint.setAntiAlias(true);
        mIconPaint.setColor(new Color(mTextItemColor));
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent event) {
        switch (event.getAction()) {
            case TouchEvent.OTHER_POINT_DOWN:
            case TouchEvent.PRIMARY_POINT_DOWN:
                return false;
            case TouchEvent.OTHER_POINT_UP:
            case TouchEvent.PRIMARY_POINT_UP:
                Rect view = new Rect(getLeft(), getTop(), getRight(), getBottom());
                Rect rect =
                        new Rect(
                                (int) event.getPointerPosition(event.getIndex()).getX() - USER_CLICK_OFFSET,
                                (int) event.getPointerPosition(event.getIndex()).getY() - USER_CLICK_OFFSET,
                                (int) event.getPointerPosition(event.getIndex()).getX() + USER_CLICK_OFFSET,
                                (int) event.getPointerPosition(event.getIndex()).getY() + USER_CLICK_OFFSET);
                if (view.getIntersectRect(rect)) {
                    mLastSelectedItem =
                            onItemClicked(
                                    new RectFloat(
                                            event.getPointerPosition(event.getIndex()).getX() - USER_CLICK_OFFSET,
                                            event.getPointerPosition(event.getIndex()).getY() - USER_CLICK_OFFSET,
                                            event.getPointerPosition(event.getIndex()).getX() + USER_CLICK_OFFSET,
                                            event.getPointerPosition(event.getIndex()).getY() + USER_CLICK_OFFSET));
                    setLastSelectedItem(mLastSelectedItem);
                    if (mCenterNavigationButton != null && mIsBtnInCenter) {
                        if (mLastSelectedItem == 2) {
                            mCenterNavigationButton.setButtonState(ButtonState.PRESSED);
                        } else {
                            mCenterNavigationButton.setButtonState(ButtonState.NORMAL);
                        }
                    }
                }
                return false;
        }
        return false;
    }

    /**
     * set OnItemSelected listener
     *
     * @param onItemSelectedListener OnItemSelectedListener
     */
    public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) {
        this.mOnItemSelectedListener = onItemSelectedListener;
    }

    /**
     * set LastSelectedItem
     *
     * @param lastSelectedItem int
     */
    public void setLastSelectedItem(int lastSelectedItem) {
        this.mLastSelectedItem = lastSelectedItem;
        if (mOnItemSelectedListener != null) {
            mOnItemSelectedListener.onItemSelected(lastSelectedItem);
        }
        invalidate();
    }

    private int onItemClicked(RectFloat rectF) {
        int cellW = (getWidth() / 5);
        for (int i = 0; i < 5; i++) {
            int startCell = i != 0 ? (i * cellW) : 0;
            int endCell = startCell + cellW;

            RectFloat cellRect = new RectFloat(startCell, 0, endCell, getBottom());
            if (rectF.getIntersectRect(cellRect)) {
                return i;
            }
        }

        return 0;
    }

    private void drawMenu(Canvas canvas) {
        if (mBtnTextStr != null) {
            for (int i = 0; i < mBtnTextStr.length; i++) {
                ColorFilter filter =
                        new ColorFilter(i != mLastSelectedItem ? mTextItemColor : mItemSelectedColor, BlendMode.SRC_IN);

                mTextPaint.setColor(new Color(i != mLastSelectedItem ? mTextItemColor : mItemSelectedColor));
                mIconPaint.setColor(new Color(i != mLastSelectedItem ? mTextItemColor : mItemSelectedColor));
                mIconPaint.setColorFilter(filter);

                String itemStr = mBtnTextStr[i];
                textRect.modify(mTextPaint.getTextBounds(itemStr));

                int cellW = (getWidth() / mBtnTextStr.length);
                int startText =
                        (i != 0
                                ? (i * cellW) + cellW / 2 - textRect.getWidth() / 2
                                : cellW / 2 - textRect.getWidth() / 2);
                canvas.drawText(mTextPaint, itemStr, startText, getHeight() - (textRect.getHeight() / 1.5F));

                if (mVectorPixelMapElement != null && i != 2) {
                    VectorPixelMap vectorPixelMap;
                    if (i < 2) {
                        vectorPixelMap = mVectorPixelMapElement[i];
                    } else {
                        vectorPixelMap = mVectorPixelMapElement[i - 1];
                    }
                    VectorElement[] vectorElements = vectorPixelMap.getElement();
                    VectorElement e = (i != mLastSelectedItem ? vectorElements[0] : vectorElements[1]);
                    int startIcon =
                            i != 0
                                    ? (i * cellW) + cellW / 2 - vectorPixelMap.getWidth() / 2
                                    : cellW / 2 - vectorPixelMap.getWidth() / 2;
                    float dy = getHeight() / 1.7F - vectorPixelMap.getHeight();
                    e.setBounds(0, 0, vectorPixelMap.getWidth(), vectorPixelMap.getHeight());
                    canvas.translate(startIcon, dy);
                    e.drawToCanvas(canvas);
                    canvas.translate(-startIcon, -dy);
                }
            }
        }
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        mBackPath.rewind();
        mRadiusRect.modify(0, mShadowRadius, mTopLeftRadius * 2, mTopLeftRadius * 1.5F);
        mBackPath.moveTo(0, mShadowRadius);
        mBackPath.arcTo(mRadiusRect, 180, 90, false);

        if (mIsBtnInCenter) {
            mBackPath.lineTo(getCenter() - mCutoutDeep - (mBnbCutoutLeftTop_radius * 2), mShadowRadius);
            // Center cutout radius top left
            mRadiusRect.modify(
                    (getCenter() - mCutoutDeep - (mBnbCutoutLeftTop_radius * 2)),
                    mShadowRadius,
                    getCenter() - mCutoutDeep,
                    mBnbCutoutLeftTop_radius * 2);
            mBackPath.arcTo(mRadiusRect, 270, 90, false);

            // Center cutout left bottom
            mRadiusRect.modify(
                    (getCenter() - mCutoutDeep),
                    -(mShadowRadius + mBnbCutoutBottomLeft_radius / 1.6F),
                    getCenter() + mBnbCutoutBottomLeft_radius,
                    mCutoutButtonOffset);
            mBackPath.arcTo(mRadiusRect, 180, -90, false);

            // Center cutout right bottom
            mRadiusRect.modify(
                    (getCenter() - mBnbCutoutBottomRight_radius),
                    -(mShadowRadius + mBnbCutoutBottomRight_radius / 1.6F),
                    getCenter() + mCutoutDeep,
                    mCutoutButtonOffset);
            mBackPath.arcTo(mRadiusRect, 90, -90, false);

            // Center cutout radius top right
            mRadiusRect.modify(
                    (getCenter() + mCutoutDeep),
                    mShadowRadius,
                    getCenter() + mCutoutDeep + (mBnbCutoutRightTop_radius * 2),
                    mBnbCutoutRightTop_radius * 2);
            mBackPath.arcTo(mRadiusRect, 180, 90, false);
        }

        mRadiusRect.modify(
                getWidth() - ((mTopRightRadius * 2) + mShadowRadius),
                mShadowRadius,
                getWidth(),
                (mTopRightRadius * 1.5F) + mShadowRadius);
        mBackPath.lineTo(getWidth() - mShadowRadius, mShadowRadius);
        mBackPath.arcTo(mRadiusRect, 270, 90, false);

        mBackPath.lineTo(getWidth(), getHeight());
        mBackPath.lineTo(0, getHeight());
        mBackPath.lineTo(0, mShadowRadius + mTopLeftRadius);
        mBackPath.close();

        canvas.drawPath(mBackPath, mBackPaint);
        drawMenu(canvas);
    }

    /**
     * 设置几个button的Element（包含正常态与选中太）及其宽高
     *
     * @param ff VectorPixelMap
     */
    public void setVectorPixelMap(VectorPixelMap... ff) {
        if (ff == null || ff.length == 0) {
            return;
        }
        this.mVectorPixelMapElement = ff.clone();
        invalidate();
    }

    /**
     * 设置button的Text
     *
     * @param strings String[]
     */
    public void setBtnContentText(String[] strings) {
        if (strings == null) {
            return;
        }
        this.mBtnTextStr = strings.clone();
        invalidate();
    }

    private float getCenter() {
        return getWidth() / 2F;
    }
}
